perm filename STRUCT.PAL[SYS,HE] blob
sn#121467 filedate 1975-02-07 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00011 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00002 00002 .SBTTL data structure processing routines
C00005 00003 Create a data block of length LENG with ID NEW.
C00007 00004
C00008 00005 delete data block pointed to by OLD and merge if possible
C00010 00006 garbage collection routines
C00013 00007 .SBTTL Monitor command routines
C00015 00008
C00017 00009
C00020 00010
C00022 00011
C00024 ENDMK
C⊗;
.SBTTL data structure processing routines
; Data structure is composed of variable length blocks. Each
; block has a three word header as follows:
; 1 pointer to first word of block in front of it
; 0 if first block
; 2 number of words in block (including header)
; 3 block ID (0 if deleted block
; STRUSE points to first block created (0 if none). ENDUSE points
; to last block created (0 if none). STRFRE points to first word
; of free storage (word following last block). ENDFRE points to
; last word of free storage. Deleted blocks are flagged and left
; in place. New blocks are created from smallest deleted block
; equal to or larger than size needed. If none, free core is used
; to create a new block. If there is not enough free core, garbage
; collection occurs. Flag DELFLG tells us if there are any deleted
; blocks. This is not the most efficient method but it is easy to
; code and has little overhead unless their are lots of small blocks.
; Search data blocks for ID on stack and replace ID with address of
; block (0 if ID not found) skipping over header words
SEARCH: MOV STRUSE,A ;start of data blocks
BEQ NONE ;no data blocks
SLOOP: CMP 2(SP),4(A) ;compare IDs
BEQ OK ;found a match
ADD 2(A),A ;get next block
CMP A,STRFRE ;test for end of data blocks
BNE SLOOP
NONE: CLR 2(SP) ;no match - clear arg
RTS PC
OK: ADD #6,A ;skip over header
MOV A,2(SP) ;match - store address in arg
RTS PC
; Create a data block of length LENG with ID NEW.
; Replace NEW with address of block (0 if not enough room)
CREATE: TST DELFLG
BEQ NODEL ;no deleted blocks - skip search
CLR B ;B points to best block found
MOV #HCOR,C ;C is length of best block found
MOV STRUSE,A ;A points to current block
CLOOP: TST 4(A)
BNE CNEXT ;test for deleted block
CMP LENG,2(A) ;deleted - test length
BGT CNEXT ;too short
CMP 2(A),C ;ok - test against best
BGT CNEXT ;too long
MOV 2(A),C ;ok - save a best block
MOV A,B
CNEXT: ADD 2(A),A ;get next block
CMP A,STRFRE ;test for end
BNE CLOOP
TST B
BEQ NODEL ;no suitable blocks found
DEC DELFLG ;this deleted block now in use
MOV NEW,4(B) ;store ID
MOV B,NEW ;replace ID with address in NEW
MOV C,A
SUB LENG,A ;number of extra bytes
CMP #6,A
BLE BRK ;≥6, break up
RTS PC ;use entire block
BRK: MOV LENG,2(NEW) ;break block into two blocks
MOV B,-(SP)
ADD LENG,B ;start of second block
MOV (SP)+,(B) ;back link
MOV A,2(B) ;new count
CLR 4(B) ;deleted
INC DELFLG
ADD B,A ;next block
CMP A,STRFRE
BGE BEND ;last block
MOV B,(A) ;back link to current block
BEND: RTS PC
NODEL: MOV ENDFRE,A ;no data blocks can be used
SUB STRFRE,A ;check for enough free core
CMP LENG,A
BLT NOGARB
TST DELFLG
BEQ NOCORE ;nothing to garbage collect
JSR PC,GARCOL ;no - garbage collect
MOV ENDFRE,A ;and try again
SUB STRFRE,A
CMP LENG,A
BLT NOGARB
NOCORE: CLR NEW ;still not enough - fail
RTS PC
NOGARB: MOV STRFRE,A ;create new block and link
TST STRUSE
BNE INTALL
MOV A,STRUSE ;initialize for first block
INTALL: MOV ENDUSE,(A)+ ;set up header
MOV LENG,(A)+
MOV NEW,(A)+
MOV STRFRE,NEW ;relink data structure
MOV STRFRE,ENDUSE
ADD LENG,STRFRE
RTS PC
; delete data block pointed to by OLD and merge if possible
DELET: MOV OLD,A
INC DELFLG
CLR 4(A) ; flag block deleted
MOV (A),C ; get back pointer
BEQ DSTR ; this is first block
TST 4(C) ; is preceding block deleted
BNE DSTR
ADD 2(A),2(C) ; yes - merge them
DEC DELFLG
MOV C,A
ADD 2(A),A
MOV C,(A)
MOV C,A
DSTR: MOV A,B ; get next block
ADD 2(B),A
CMP STRFRE,A
BLE DNO ; this is last block
TST 4(A) ; is next block deleted
BNE DNO1
ADD 2(A),2(B) ; yes - merge them
DEC DELFLG
ADD 2(A),A ; and get next block
MOV C,(A) ; deposit back pointer
DNO1: RTS PC
DNO: MOV B,STRFRE ; last block of list deleted
DEC DELFLG ; add it to free storage
MOV (B),ENDUSE
BEQ DATINT ; no blocks in use - initialize
RTS PC
; Initialize data structure when empty
DATINT: CLR STRUSE
CLR ENDUSE
MOV #FREE,STRFRE
CLR DELFLG
RTS PC
; garbage collection routines
GARCOL: MOV STRUSE,A ;A is where next used block should go
MOV A,B ;B is current block being checked
CLR C ;C is pointer to last block
CLR DELFLG ;no deletions
MOV LENG,-(SP) ;save this register
GLOOP: TST 4(B) ;test for deleted block
BEQ GDEL
CMP A,B ;no - have we deleted anything yet
BEQ NOPACK ;no
MOV 2(B),LENG ;yes - get length of this block
ASR LENG ; in words
MOV A,-(SP) ;save current pointer
PLOOP: MOV (B)+,(A)+ ;move block to new location
SOB LENG,PLOOP
MOV C,@(SP) ;back link for moved block
MOV (SP)+,C ;and save next back link
BR NEXT
NOPACK: MOV B,C ;nothing to move - save next back link
ADD 2(B),A ;skip good block
GDEL: ADD 2(B),B ;deleted block - skip it
NEXT: CMP B,STRFRE
BLT GLOOP
CMP A,STRUSE
BNE UPD
JSR PC,DATINT ;no used block - reinitialize structure
BR NULL
UPD: MOV C,ENDUSE ;finished, update pointers to blocks
MOV A,STRFRE
NULL: MOV (SP)+,LENG
RTS PC
FNDEND: TST ENDFRE ;find highest location useable for free core
BNE FOUT ; already found
MOV #FREE,A
FLOOP: TST 2(A) ; test next location for zero
BNE FNXT
ADD #2,A
CMP A,#HCOR ; test for end of core
BLT FLOOP
FNXT: MOV A,ENDFRE ; found - save for future calls
SUB #FREE-2,A ; get number of free words
MOV A,ENDUSE ; and tell user
CRLF
NUMDEC ENDUSE
OUTSTR FREMES
CRLF
FOUT: RTS PC
.SBTTL Monitor command routines
COM1: MOV IBUF+2,NEW ;get arguments
MOV IBUF+4,OLD
MOV IBUF+6,LENG
CLR OBUF+2 ;clear error code and address
CLR OBUF+4
ADD #3,LENG ;adjust length for header
ASL LENG ;and convert to bytes
TST OLD
BGT OLDOK
TST NEW
BGT NEWOK
NOID: MOV #20,OBUF+4 ;both IDs =0, set warning flag
BR ERRRET
OLDOK: MOV OLD,-(SP) ;old ID given, find it
JSR PC,SEARCH
MOV (SP)+,OLD
BNE OLDFND
BIS #10,OBUF+4 ;not found, set error flag
TST NEW
BGT NEWOK ;and process new ID
BR NOID ; if any
OLDFND: SUB #6,OLD ;point to header
TST NEW
BGT FNDNEW
JSR PC,DELET ;no new ID, just delete old block
BR ERRRET
FNDNEW: MOV NEW,-(SP) ;both old and new ID, find new one
JSR PC,SEARCH
TST (SP)
BEQ USENEW ;new ID does not exist - ok
SUB #6,(SP) ;point to header
CMP (SP),OLD
BEQ USENEW ;new ID = old ID - OK
IGLNEW: BIS #4,OBUF+4 ;new ID already exists - fatal error
ADD #2,SP ;flush stack
BR ERRRET
USENEW: CMP LENG,2(OLD) ;are old and new blocks same size?
BNE DELOLD ;no (sigh!!)
MOV NEW,4(OLD) ;yes - use it
MOV OLD,OBUF+2
ADD #6,OBUF+2 ;skip header
BR ERRRET
DELOLD: JSR PC,DELET ;delete old block
BR NEWSEA ;and go to create a new block
NEWOK: MOV NEW,-(SP) ;not old ID, search for new ID
JSR PC,SEARCH
TST (SP)
BNE IGLNEW ;new ID must not exist
NEWSEA: ADD #2,SP ;flush stack
CMP LENG,#3 ;test size
BGT LENOK
BIS #2,OBUF+4 ;length≤0, fatal error
BR ERRRET
LENOK: JSR PC,CREATE ;create a new block
TST NEW
BGT CREOK
BIS #1,OBUF+4
BR ERRRET ;no room for block
CREOK: MOV NEW,OBUF+2 ;save block address
ADD #6,OBUF+2 ;skip header
BR ERRRET
; Block status command
COM2: CLR OBUF+2
CLR OBUF+4
MOV IBUF+2,-(SP) ;search for block
BLE ERRRET ;null id given
JSR PC,SEARCH
MOV (SP)+,OBUF+2
BEQ ERRRET ;does not exist
MOV OBUF+2,A
MOV -4(A),B ;exists, return length also
ASR B ;convert to words
SUB #3,B
MOV B,OBUF+4 ;adjust length for header
ERRRET: MOV COMAND,OBUF ;return command
JMP WAITX
; COMMAND #3 - repack picture data blocks
; argument is ID of control block of form:
PICT=0 ; ID of picture data block to be repacked
NLFT=2 ; new X coordinate of left side of rectangle
NTOP=4 ; new Y coordinate of top side of rectangle
NSP=6 ; new number of samples per line
NLN=10 ; new number of lines in picture
; NLFT will be adjusted out to next word boundary and updated, along
; with NSP in control block. Excess space in data block, if any,
; will be returned to free storage. Argument returned is size, in
; words, of new picture block, which will have the same address as
; the old one. The error word returned is decoded as follows:
; 1 new limits outside old limits - not repacked
; 0 repacking finished
; -1 did not find control block
; -2 did not find picture data block
OBYT: 0 ; difference in line lengths in bytes
NSIZ: 0 ; new picture size in bytes
NWLN: 0 ; new # of words/line
LOFFS: 0 ; first line of new picture relative to old
SOFFS: 0 ; first byte of new picture line relative to old
COM3: CLR OBUF+2
CLR OBUF+4
MOV IBUF+2,-(SP) ; put control block in NEW
JSR PC,SEARCH
MOV (SP)+,NEW
BNE BLKFND
MOV #-1,OBUF+4 ; error -1, block not found
BR ERRRET
BLKFND: MOV PICT(NEW),-(SP) ; put picture block in OLD
JSR PC,SEARCH
MOV (SP)+,OLD
BNE B2FL
MOV #-2,OBUF+4 ; error -2, block not found
BR ERRRET
B2FL: SUB LEFT(OLD),NLFT(NEW) ; adjust new limits to word boundary
BGE LAB31
BLKOUT: MOV #1,OBUF+4 ; error 1 - limits outside old
BR ERRRET
LAB31: MOV NLFT(NEW),A
BIC #3,NLFT(NEW)
MOV NLFT(NEW),SOFFS
ASR SOFFS ; save byte offset
SUB NLFT(NEW),A
ADD A,NSP(NEW)
ADD LEFT(OLD),NLFT(NEW)
MOV NTOP(NEW),LOFFS ; save line offset
SUB TOP(OLD),LOFFS
BLT BLKOUT
CMP NSP(NEW),NSAMP(OLD)
BGT BLKOUT
CMP NLN(NEW),NLIN(OLD)
BGT BLKOUT
MOV NSP(NEW),NWLN ; compute new parameters
ADD #4,NWLN
ASR NWLN
ASR NWLN ; new words per line
MOV WRDLIN(OLD),OBYT
SUB NWLN,OBYT
ASL OBYT ; bytes/line difference
MOV NLN(NEW),B
MUL NWLN,B
ASL B
MOV B,NSIZ ; new picture size
MOV OLD,A ; set up copy
ADD PPNTR(OLD),A ; start of old picture in A
MOV WRDLIN(OLD),B
MUL LOFFS,B
ASL B
ADD A,B
ADD SOFFS,B ; start of new picture in B
MOV NLN(NEW),LENG ; line count to copy in LENG
LAB32: MOV NWLN,C ; word count to copy in C
LAB33: MOV (B)+,(A)+ ; this copies
SOB C,LAB33 ; takes care of full line
ADD OBYT,B ; increment pointer to next line
SOB LENG,LAB32 ; wasn't this easy !!!
MOV NLFT(NEW),LEFT(OLD) ; copy new parameters
MOV NTOP(NEW),TOP(OLD)
MOV NSP(NEW),NSAMP(OLD)
MOV NLN(NEW),NLIN(OLD)
MOV NWLN,WRDLIN(OLD)
MOV NSIZ,PSIZE(OLD)
ADD PPNTR(OLD),NSIZ ; compute new picture block size
ADD #6,NSIZ
SUB #6,OLD
MOV 2(OLD),LENG ; old block size in LENG
MOV LENG,C
SUB NSIZ,LENG ; number of excess words
CMP #3,LENG
BGT NOBRK ; not enough - keep old size
MOV NSIZ,2(OLD) ; break up old block - set new leng
ADD OLD,C ; start of next block
MOV NSIZ,NEW
ADD OLD,NEW ; start of deleted block
MOV LENG,2(NEW)
CMP C,STRFRE
BGE BEND1
MOV NEW,(C) ; relink blocks
BEND1: MOV OLD,(NEW)
MOV OLD,-(SP)
MOV NEW,OLD
JSR PC,DELET
MOV (SP)+,OLD
NOBRK: MOV 2(OLD),OBUF+2 ; return new block size
SUB #3,OBUF+2
JMP ERRRET